//////////////////////////////////////////////////////////////////////////
#pragma once
#pragma managed
//////////////////////////////////////////////////////////////////////////
NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////
public ref class StatModel abstract
{
protected:
	~StatModel()
	{
		if (m_pStatModel != NULL)
		{
			delete m_pStatModel;
			m_pStatModel = NULL;
		}
	}

public:
	void clear()
	{
		m_pStatModel->clear();
	}

	void save(IntPtr filename)
	{
		m_pStatModel->save((char*)filename.ToPointer());
	}

	void load(IntPtr filename)
	{
		m_pStatModel->load((char*)filename.ToPointer());
	}

	void save(IntPtr filename, IntPtr name)
	{
		m_pStatModel->save((char*)filename.ToPointer(), (char*)name.ToPointer());
	}

	void load(IntPtr filename, IntPtr name)
	{
		m_pStatModel->load((char*)filename.ToPointer());
	}

	void write(IntPtr storage, IntPtr name)
	{
		m_pStatModel->write((CvFileStorage*)storage.ToPointer(), (char*)name.ToPointer());
	}

	void read(IntPtr storage, IntPtr node)
	{
		m_pStatModel->read((CvFileStorage*)storage.ToPointer(), (CvFileNode*)node.ToPointer());
	}

protected:
	CvStatModel* m_pStatModel;
};

/****************************************************************************************\
*                                 Normal Bayes Classifier                                *
\****************************************************************************************/
public ref class NormalBayesClassifier : public StatModel
{
public:
	NormalBayesClassifier()
	{
		m_pStatModel = new CvNormalBayesClassifier();
	}

	NormalBayesClassifier(IntPtr _train_data,IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx)
	{
		m_pStatModel = new CvNormalBayesClassifier(
			(CvMat*)_train_data.ToPointer(), 
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(), 
			(CvMat*)_sample_idx.ToPointer());
	}

	NormalBayesClassifier(IntPtr _train_data,IntPtr _responses, IntPtr _var_idx)
	{
		m_pStatModel = new CvNormalBayesClassifier(
			(CvMat*)_train_data.ToPointer(), 
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer());
	}

	NormalBayesClassifier(IntPtr _train_data,IntPtr _responses)
	{
		m_pStatModel = new CvNormalBayesClassifier(
			(CvMat*)_train_data.ToPointer(), 
			(CvMat*)_responses.ToPointer());
	}

	bool train(IntPtr _train_data,IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, bool update)
	{
		return ((CvNormalBayesClassifier*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			update);
	}

	bool train(IntPtr _train_data,IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx)
	{
		return ((CvNormalBayesClassifier*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	bool train(IntPtr _train_data,IntPtr _responses, IntPtr _var_idx)
	{
		return ((CvNormalBayesClassifier*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer());
	}

	bool train(IntPtr _train_data,IntPtr _responses)
	{
		return ((CvNormalBayesClassifier*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer());
	}

	float predict(IntPtr _samples, IntPtr results)
	{
		return ((CvNormalBayesClassifier*)m_pStatModel)->predict(
			(CvMat*)_samples.ToPointer(),
			(CvMat*)results.ToPointer());
	}

	float predict(IntPtr _samples)
	{
		return ((CvNormalBayesClassifier*)m_pStatModel)->predict((CvMat*)_samples.ToPointer());
	}
};

/****************************************************************************************\
*                          K-Nearest Neighbour Classifier                                *
\****************************************************************************************/
public ref class KNearest : public StatModel
{
public:
	KNearest()
	{
		m_pStatModel = new CvKNearest();
	}

	KNearest(IntPtr _train_data, IntPtr _responses, IntPtr _sample_idx, bool _is_regression, int max_k)
	{
		m_pStatModel = new CvKNearest(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			_is_regression,
			max_k);
	}

	KNearest(IntPtr _train_data, IntPtr _responses, IntPtr _sample_idx, bool _is_regression)
	{
		m_pStatModel = new CvKNearest(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			_is_regression);
	}

	KNearest(IntPtr _train_data, IntPtr _responses, IntPtr _sample_idx)
	{
		m_pStatModel = new CvKNearest(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	KNearest(IntPtr _train_data, IntPtr _responses)
	{
		m_pStatModel = new CvKNearest(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer());
	}

	bool train(IntPtr _train_data, IntPtr _responses, IntPtr _sample_idx, bool is_regression, int _max_k, bool _update_base)
	{
		return ((CvKNearest*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			is_regression,
			_max_k,
			_update_base);
	}

	bool train(IntPtr _train_data, IntPtr _responses, IntPtr _sample_idx, bool is_regression, int _max_k)
	{
		return ((CvKNearest*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			is_regression,
			_max_k);
	}

	bool train(IntPtr _train_data, IntPtr _responses, IntPtr _sample_idx, bool is_regression)
	{
		return ((CvKNearest*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			is_regression);
	}

	bool train(IntPtr _train_data, IntPtr _responses, IntPtr _sample_idx)
	{
		return ((CvKNearest*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	bool train(IntPtr _train_data, IntPtr _responses)
	{
		return ((CvKNearest*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer());
	}

	float find_nearest(IntPtr _samples, int k, IntPtr results, IntPtr neighbors, IntPtr neighbor_responses, IntPtr dist)
	{
		return ((CvKNearest*)m_pStatModel)->find_nearest(
			(CvMat*)_samples.ToPointer(),
			k,
			(CvMat*)results.ToPointer(),
			(const float**)neighbors.ToPointer(),
			(CvMat*)neighbor_responses.ToPointer(),
			(CvMat*)dist.ToPointer());
	}

	float find_nearest(IntPtr _samples, int k, IntPtr results, IntPtr neighbors, IntPtr neighbor_responses)
	{
		return ((CvKNearest*)m_pStatModel)->find_nearest(
			(CvMat*)_samples.ToPointer(),
			k,
			(CvMat*)results.ToPointer(),
			(const float**)neighbors.ToPointer(),
			(CvMat*)neighbor_responses.ToPointer());
	}

	float find_nearest(IntPtr _samples, int k, IntPtr results, IntPtr neighbors)
	{
		return ((CvKNearest*)m_pStatModel)->find_nearest(
			(CvMat*)_samples.ToPointer(),
			k,
			(CvMat*)results.ToPointer(),
			(const float**)neighbors.ToPointer());
	}

	float find_nearest(IntPtr _samples, int k, IntPtr results)
	{
		return ((CvKNearest*)m_pStatModel)->find_nearest(
			(CvMat*)_samples.ToPointer(),
			k,
			(CvMat*)results.ToPointer());
	}

	float find_nearest(IntPtr _samples, int k)
	{
		return ((CvKNearest*)m_pStatModel)->find_nearest(
			(CvMat*)_samples.ToPointer(),
			k);
	}

	int get_max_k()
	{
		return ((CvKNearest*)m_pStatModel)->get_max_k();
	}

	int get_var_count()
	{
		return ((CvKNearest*)m_pStatModel)->get_var_count();
	}

	int get_sample_count()
	{
		return ((CvKNearest*)m_pStatModel)->get_sample_count();
	}

	bool is_regression()
	{
		return ((CvKNearest*)m_pStatModel)->is_regression();
	}
};

/****************************************************************************************\
*                                   Support Vector Machines                              *
\****************************************************************************************/
public ref class SVM : public StatModel
{
public:
	SVM()
	{
		m_pStatModel = new CvSVM();
	}

	SVM(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params)
	{
		m_pStatModel = new CvSVM(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params);
	}

	SVM(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx)
	{
		m_pStatModel = new CvSVM(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	SVM(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx)
	{
		m_pStatModel = new CvSVM(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer());
	}

	SVM(IntPtr _train_data, IntPtr _responses)
	{
		m_pStatModel = new CvSVM(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer());
	}

	bool train(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params)
	{
		return ((CvSVM*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params);
	}

	bool train(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx)
	{
		return ((CvSVM*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	bool train(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx)
	{
		return ((CvSVM*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer());
	}

	bool train(IntPtr _train_data, IntPtr _responses)
	{
		return ((CvSVM*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer());
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params,
		int k_fold, ParamGrid C_grid, ParamGrid gamma_grid, ParamGrid p_grid, ParamGrid nu_grid, ParamGrid coef_grid, ParamGrid degree_grid)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params,
			k_fold,
			*(CvParamGrid*)&C_grid,
			*(CvParamGrid*)&gamma_grid,
			*(CvParamGrid*)&p_grid,
			*(CvParamGrid*)&nu_grid,
			*(CvParamGrid*)&coef_grid, 
			*(CvParamGrid*)&degree_grid);
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params,
		int k_fold, ParamGrid C_grid, ParamGrid gamma_grid, ParamGrid p_grid, ParamGrid nu_grid, ParamGrid coef_grid)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params,
			k_fold,
			*(CvParamGrid*)&C_grid,
			*(CvParamGrid*)&gamma_grid,
			*(CvParamGrid*)&p_grid,
			*(CvParamGrid*)&nu_grid,
			*(CvParamGrid*)&coef_grid);
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params,
		int k_fold, ParamGrid C_grid, ParamGrid gamma_grid, ParamGrid p_grid, ParamGrid nu_grid)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params,
			k_fold,
			*(CvParamGrid*)&C_grid,
			*(CvParamGrid*)&gamma_grid,
			*(CvParamGrid*)&p_grid,
			*(CvParamGrid*)&nu_grid);
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params,
		int k_fold, ParamGrid C_grid, ParamGrid gamma_grid, ParamGrid p_grid)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params,
			k_fold,
			*(CvParamGrid*)&C_grid,
			*(CvParamGrid*)&gamma_grid,
			*(CvParamGrid*)&p_grid);
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params,
		int k_fold, ParamGrid C_grid, ParamGrid gamma_grid)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params,
			k_fold,
			*(CvParamGrid*)&C_grid,
			*(CvParamGrid*)&gamma_grid);
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params,
		int k_fold, ParamGrid C_grid)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params,
			k_fold,
			*(CvParamGrid*)&C_grid);
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params,
		int k_fold)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params,
			k_fold);
	}

	bool train_auto(IntPtr _train_data, IntPtr _responses, IntPtr _var_idx, IntPtr _sample_idx, SVMParams _params)
	{
		return ((CvSVM*)m_pStatModel)->train_auto(
			(CvMat*)_train_data.ToPointer(),
			(CvMat*)_responses.ToPointer(),
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(),
			*(CvSVMParams*)&_params);
	}

	float predict(IntPtr _sample, bool returnDFVal)
	{
		return ((CvSVM*)m_pStatModel)->predict((CvMat*)_sample.ToPointer(), returnDFVal);
	}

	float predict(IntPtr _sample)
	{
		return ((CvSVM*)m_pStatModel)->predict((CvMat*)_sample.ToPointer());
	}

	int get_support_vector_count()
	{
		return ((CvSVM*)m_pStatModel)->get_support_vector_count();
	}

	IntPtr get_support_vector(int i)
	{
		return IntPtr((void*)((CvSVM*)m_pStatModel)->get_support_vector(i));
	}

	SVMParams get_params()
	{
		return *(SVMParams*)&(((CvSVM*)m_pStatModel)->get_params());
	}

	static ParamGrid get_default_grid(int param_id)
	{
		return *(ParamGrid*)&(CvSVM::get_default_grid((int)param_id));
	}

	int get_var_count()
	{
		return ((CvSVM*)m_pStatModel)->get_var_count();
	}
};

/****************************************************************************************\
*                              Expectation - Maximization                                *
\****************************************************************************************/
public ref class EM : public StatModel
{
public:
	EM()
	{
		m_pStatModel = new CvEM();
	}

	EM(IntPtr samples, IntPtr sample_idx, EMParams params, IntPtr labels)
	{
		m_pStatModel = new CvEM((CvMat*)samples.ToPointer(), (CvMat*)sample_idx.ToPointer(), *(CvEMParams*)&params, (CvMat*)labels.ToPointer());
	}

	EM(IntPtr samples, IntPtr sample_idx, EMParams params)
	{
		m_pStatModel = new CvEM((CvMat*)samples.ToPointer(), (CvMat*)sample_idx.ToPointer(), *(CvEMParams*)&params);
	}

	EM(IntPtr samples, IntPtr sample_idx)
	{
		m_pStatModel = new CvEM((CvMat*)samples.ToPointer(), (CvMat*)sample_idx.ToPointer());
	}

	EM(IntPtr samples)
	{
		m_pStatModel = new CvEM((CvMat*)samples.ToPointer());
	}

	bool train(IntPtr samples, IntPtr sample_idx, EMParams params, IntPtr labels)
	{
		return ((CvEM*)m_pStatModel)->train((CvMat*)samples.ToPointer(), (CvMat*)sample_idx.ToPointer(), *(CvEMParams*)&params, (CvMat*)labels.ToPointer());
	}

	bool train(IntPtr samples, IntPtr sample_idx, EMParams params)
	{
		return ((CvEM*)m_pStatModel)->train((CvMat*)samples.ToPointer(), (CvMat*)sample_idx.ToPointer(), *(CvEMParams*)&params);
	}

	bool train(IntPtr samples, IntPtr sample_idx)
	{
		return ((CvEM*)m_pStatModel)->train((CvMat*)samples.ToPointer(), (CvMat*)sample_idx.ToPointer());
	}

	bool train(IntPtr samples)
	{
		return ((CvEM*)m_pStatModel)->train((CvMat*)samples.ToPointer());
	}

	float predict(IntPtr sample,IntPtr probs)
	{
		return ((CvEM*)m_pStatModel)->predict((CvMat*)sample.ToPointer(), (CvMat*)probs.ToPointer());
	}

	int get_nclusters()
	{
		return ((CvEM*)m_pStatModel)->get_nclusters();
	}

	IntPtr get_means()
	{
		return IntPtr((void*)((CvEM*)m_pStatModel)->get_means());
	}

	IntPtr get_covs()
	{
		return IntPtr((void*)((CvEM*)m_pStatModel)->get_covs());
	}

	IntPtr get_weights()
	{
		return IntPtr((void*)((CvEM*)m_pStatModel)->get_weights());
	}

	IntPtr get_probs()
	{
		return IntPtr((void*)((CvEM*)m_pStatModel)->get_probs());
	}

	double get_log_likelihood()
	{
		return ((CvEM*)m_pStatModel)->get_log_likelihood();
	}


};

/****************************************************************************************\
*                                      Decision Tree                                     *
\****************************************************************************************/\
public ref class DTreeTrainData
{
public:
	DTreeTrainData()
	{
		m_pDTreeTrainData = new CvDTreeTrainData();
	}

	~DTreeTrainData()
	{
		delete m_pDTreeTrainData;
	}

internal:
	DTreeTrainData(CvDTreeTrainData* pDTreeTrainData)
	{
		m_pDTreeTrainData = pDTreeTrainData;
	}

	CvDTreeTrainData* GetRawPointer()
	{
		return m_pDTreeTrainData; 
	}

private:
	CvDTreeTrainData* m_pDTreeTrainData;
};

public ref class DTree : public StatModel
{
public:
	DTree() 
	{
		m_pStatModel = new CvDTree();
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask,
		DTreeParams params)
	{
		return ((CvDTree*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer(),
			*(CvDTreeParams*)&params);
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask)
	{
		return ((CvDTree*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type)
	{
		return ((CvDTree*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx)
	{
		return ((CvDTree*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx)
	{
		return ((CvDTree*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses)
	{
		return ((CvDTree*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer());
	}

	bool train(IntPtr _data, DTreeParams _params)
	{
		return ((CvDTree*)m_pStatModel)->train((CvMLData*)_data.ToPointer(), *(CvDTreeParams*)&_params);
	}

	bool train(IntPtr _data)
	{
		return ((CvDTree*)m_pStatModel)->train((CvMLData*)_data.ToPointer());
	}

	float calc_error(IntPtr _data, MlErrorType type , IntPtr resp)
	{
		return ((CvDTree*)m_pStatModel)->calc_error((CvMLData*)_data.ToPointer(), (int)type, (vector<float>*)resp.ToPointer());
	}

	float calc_error(IntPtr _data, MlErrorType type)
	{
		return ((CvDTree*)m_pStatModel)->calc_error((CvMLData*)_data.ToPointer(), (int)type);
	}

	bool train(IntPtr _train_data, IntPtr _subsample_idx)
	{
		return ((CvDTree*)m_pStatModel)->train((CvDTreeTrainData*)_train_data.ToPointer(), (CvMat*)_subsample_idx.ToPointer());
	}

	IntPtr predict(IntPtr _sample, IntPtr _missing_data_mask, bool preprocessed_input)
	{
		return IntPtr((CvDTreeNode*)((CvDTree*)m_pStatModel)->predict((CvMat*)_sample.ToPointer(), (CvMat*)_missing_data_mask.ToPointer(), preprocessed_input));
	}

	IntPtr predict(IntPtr _sample, IntPtr _missing_data_mask)
	{
		return IntPtr((CvDTreeNode*)((CvDTree*)m_pStatModel)->predict((CvMat*)_sample.ToPointer(), (CvMat*)_missing_data_mask.ToPointer()));
	}

	IntPtr predict(IntPtr _sample)
	{
		return IntPtr((CvDTreeNode*)((CvDTree*)m_pStatModel)->predict((CvMat*)_sample.ToPointer()));
	}

	IntPtr get_var_importance()
	{
		return IntPtr((CvMat*)((CvDTree*)m_pStatModel)->get_var_importance());
	}

	// special read & write methods for trees in the tree ensembles
	void read(IntPtr fs, IntPtr node, IntPtr data)
	{
		return ((CvDTree*)m_pStatModel)->read((CvFileStorage*)fs.ToPointer(), (CvFileNode*)node.ToPointer(), (CvDTreeTrainData*)data.ToPointer());
	}

	void write(IntPtr fs)
	{
		return ((CvDTree*)m_pStatModel)->write((CvFileStorage*)fs.ToPointer());
	}

	IntPtr get_root()
	{
		return IntPtr((CvDTreeNode*)((CvDTree*)m_pStatModel)->get_root());
	}

	int get_pruned_tree_idx()
	{
		return ((CvDTree*)m_pStatModel)->get_pruned_tree_idx();
	}

	IntPtr get_data()
	{
		return IntPtr(((CvDTree*)m_pStatModel)->get_data());
	}
};

/****************************************************************************************\
*                                   Random Trees Classifier                              *
\****************************************************************************************/
public ref class ForestTree : DTree
{
public:
	ForestTree()
	{
		m_pStatModel = new CvForestTree();
	}

	bool train(IntPtr _train_data, IntPtr _subsample_idx, IntPtr forest)
	{
		return ((CvForestTree*)m_pStatModel)->train(
			(CvDTreeTrainData*)_train_data.ToPointer(), 
			(const CvMat*)_subsample_idx.ToPointer(), 
			(CvRTrees*)forest.ToPointer());
	}

	int get_var_count() 
	{
		return ((CvForestTree*)m_pStatModel)->get_var_count();
	}

	void read(IntPtr fs, IntPtr node, IntPtr forest, IntPtr _data)
	{
		return ((CvForestTree*)m_pStatModel)->read(
			(CvFileStorage*)fs.ToPointer(),
			(CvFileNode*)node.ToPointer(),
			(CvRTrees*)forest.ToPointer(),
			(CvDTreeTrainData*)_data.ToPointer());
	}

};

public ref class RTrees : public StatModel
{
public:
	RTrees()
	{
		m_pStatModel = new CvRTrees();
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask,
		RTParams params)
	{
		return ((CvRTrees*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer(),
			*(CvRTParams*)&params);
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask)
	{
		return ((CvRTrees*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type)
	{
		return ((CvRTrees*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx)
	{
		return ((CvRTrees*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx)
	{
		return ((CvRTrees*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses)
	{
		return ((CvRTrees*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer());
	}

	bool train(IntPtr data, RTParams params)
	{
		return ((CvRTrees*)m_pStatModel)->train((CvMLData*)data.ToPointer(), *(CvRTParams*)&params);
	}

	bool train(IntPtr data)
	{
		return ((CvRTrees*)m_pStatModel)->train((CvMLData*)data.ToPointer());
	}

	float predict(IntPtr sample, IntPtr missing)
	{
		return ((CvRTrees*)m_pStatModel)->predict((CvMat*)sample.ToPointer(), (CvMat*)missing.ToPointer());
	}

	float predict(IntPtr sample)
	{
		return ((CvRTrees*)m_pStatModel)->predict((CvMat*)sample.ToPointer());
	}

	float predict_prob(IntPtr sample, IntPtr missing)
	{
		return ((CvRTrees*)m_pStatModel)->predict_prob((CvMat*)sample.ToPointer(), (CvMat*)missing.ToPointer());
	}

	float predict_prob(IntPtr sample)
	{
		return ((CvRTrees*)m_pStatModel)->predict_prob((CvMat*)sample.ToPointer());
	}

	IntPtr get_var_importance()
	{
		return IntPtr((CvMat*)((CvRTrees*)m_pStatModel)->get_var_importance());
	}

	float get_proximity(IntPtr sample1, IntPtr sample2, IntPtr missing1,  IntPtr missing2)
	{
		return ((CvRTrees*)m_pStatModel)->get_proximity(
			(CvMat*)sample1.ToPointer(), 
			(CvMat*)sample2.ToPointer(), 
			(CvMat*)missing1.ToPointer(), 
			(CvMat*)missing2.ToPointer());
	}

	float get_proximity(IntPtr sample1, IntPtr sample2, IntPtr missing1)
	{
		return ((CvRTrees*)m_pStatModel)->get_proximity(
			(CvMat*)sample1.ToPointer(), 
			(CvMat*)sample2.ToPointer(), 
			(CvMat*)missing1.ToPointer());
	}

	float get_proximity(IntPtr sample1, IntPtr sample2)
	{
		return ((CvRTrees*)m_pStatModel)->get_proximity(
			(CvMat*)sample1.ToPointer(), 
			(CvMat*)sample2.ToPointer());
	}

	float calc_error(IntPtr _data, MlErrorType type, IntPtr resp)
	{
		return ((CvRTrees*)m_pStatModel)->calc_error(
			(CvMLData*)_data.ToPointer(), 
			(int)type, 
			(vector<float>*)resp.ToPointer());
	}

	float calc_error(IntPtr _data, MlErrorType type)
	{
		return ((CvRTrees*)m_pStatModel)->calc_error(
			(CvMLData*)_data.ToPointer(), 
			(int)type);
	}

	float get_train_error()
	{
		return ((CvRTrees*)m_pStatModel)->get_train_error();
	}

	IntPtr get_active_var_mask()
	{
		return IntPtr(((CvRTrees*)m_pStatModel)->get_active_var_mask());
	}

	IntPtr get_rng()
	{
		return IntPtr(((CvRTrees*)m_pStatModel)->get_rng());
	}

	int get_tree_count()
	{
		return ((CvRTrees*)m_pStatModel)->get_tree_count();
	}

	IntPtr get_tree(int i)
	{
		return IntPtr(((CvRTrees*)m_pStatModel)->get_tree(i));
	}
};

/****************************************************************************************\
*                           Extremely randomized trees Classifier                        *
\****************************************************************************************/
public ref class ERTreeTrainData : public DTreeTrainData
{
public:
	ERTreeTrainData() : DTreeTrainData(new CvERTreeTrainData())
	{

	}
};

public ref class ForestERTree : public ForestTree
{
public:
	ForestERTree()
	{
		m_pStatModel = new CvForestERTree();
	}
};

public ref class ERTrees : public RTrees
{
public:
	ERTrees()
	{
		m_pStatModel = new CvERTrees();
	}
};

/****************************************************************************************\
*                                   Boosted tree classifier                              *
\****************************************************************************************/

public ref class BoostTree : public DTree
{
public:
	BoostTree()
	{
		m_pStatModel = new CvBoostTree();
	}

	bool train(IntPtr _train_data, IntPtr subsample_idx, IntPtr ensemble)
	{
		return ((CvBoostTree*)m_pStatModel)->train(
			(CvDTreeTrainData*)_train_data.ToPointer(), 
			(CvMat*) subsample_idx.ToPointer(), 
			(CvBoost*)ensemble.ToPointer());
	}

	void scale(double s)
	{
		return ((CvBoostTree*)m_pStatModel)->scale(s);
	}

	void read(IntPtr fs, IntPtr node, IntPtr ensemble, IntPtr _data)
	{
		return ((CvBoostTree*)m_pStatModel)->read(
			(CvFileStorage*)fs.ToPointer(), 
			(CvFileNode*)node.ToPointer(), 
			(CvBoost*)ensemble.ToPointer(), 
			(CvDTreeTrainData*)_data.ToPointer());
	}
};

public ref class Boost : public StatModel
{
public:
	Boost()
	{
		m_pStatModel = new CvBoost();
	}

	Boost(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask,
		BoostParams params)
	{
		m_pStatModel = new CvBoost(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer(),
			*(CvBoostParams*)&params);
	}

	Boost(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask)
	{
		m_pStatModel = new CvBoost(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer());
	}

	Boost(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type)
	{
		m_pStatModel = new CvBoost(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer());
	}

	Boost(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx)
	{
		m_pStatModel = new CvBoost(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	Boost(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx)
	{
		m_pStatModel = new CvBoost(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer());
	}

	Boost(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses)
	{
		m_pStatModel = new CvBoost(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask,
		BoostParams params,
		bool update)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer(),
			*(CvBoostParams*)&params,
			update);
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask,
		BoostParams params)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer(),
			*(CvBoostParams*)&params);
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type,
		IntPtr _missing_mask)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer(),
			(CvMat*)_missing_mask.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx, 
		IntPtr _var_type)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer(), 
			(CvMat*)_var_type.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx,
		IntPtr _sample_idx)
	{
		return ((CvDTree*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer(),
			(CvMat*)_sample_idx.ToPointer());
	}

	bool train(IntPtr _train_data, 
		int _tflag,
		IntPtr _responses, 
		IntPtr _var_idx)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer(), 
			(CvMat*)_var_idx.ToPointer());
	}

	bool train(IntPtr _train_data,  int _tflag, IntPtr _responses)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMat*)_train_data.ToPointer(), 
			_tflag,
			(CvMat*)_responses.ToPointer());
	}

	bool train(IntPtr data, BoostParams params, bool update)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMLData*)data.ToPointer(), 
			*(CvBoostParams*)&params,
			update);
	}

	bool train(IntPtr data, BoostParams params)
	{
		return ((CvBoost*)m_pStatModel)->train(
			(CvMLData*)data.ToPointer(), 
			*(CvBoostParams*)&params);
	}

	bool train(IntPtr data)
	{
		return ((CvBoost*)m_pStatModel)->train((CvMLData*)data.ToPointer());
	}

	float predict(IntPtr _sample, 
		IntPtr _missing,
		IntPtr weak_responses, 
		Slice slice,
		bool raw_mode, 
		bool return_sum )
	{
		return ((CvBoost*)m_pStatModel)->predict(
			(CvMat*)_sample.ToPointer(),
			(CvMat*)_missing.ToPointer(),
			(CvMat*)weak_responses.ToPointer(),
			*(CvSlice*)&slice,
			raw_mode,
			return_sum);
	}

	float predict(IntPtr _sample, 
		IntPtr _missing,
		IntPtr weak_responses, 
		Slice slice,
		bool raw_mode)
	{
		return ((CvBoost*)m_pStatModel)->predict(
			(CvMat*)_sample.ToPointer(),
			(CvMat*)_missing.ToPointer(),
			(CvMat*)weak_responses.ToPointer(),
			*(CvSlice*)&slice,
			raw_mode);
	}

	float predict(IntPtr _sample, 
		IntPtr _missing,
		IntPtr weak_responses, 
		Slice slice)
	{
		return ((CvBoost*)m_pStatModel)->predict(
			(CvMat*)_sample.ToPointer(),
			(CvMat*)_missing.ToPointer(),
			(CvMat*)weak_responses.ToPointer(),
			*(CvSlice*)&slice);
	}

	float predict(IntPtr _sample, 
		IntPtr _missing,
		IntPtr weak_responses)
	{
		return ((CvBoost*)m_pStatModel)->predict(
			(CvMat*)_sample.ToPointer(),
			(CvMat*)_missing.ToPointer(),
			(CvMat*)weak_responses.ToPointer());
	}

	float predict(IntPtr _sample, 
		IntPtr _missing)
	{
		return ((CvBoost*)m_pStatModel)->predict(
			(CvMat*)_sample.ToPointer(),
			(CvMat*)_missing.ToPointer());
	}

	float predict(IntPtr _sample)
	{
		return ((CvBoost*)m_pStatModel)->predict((CvMat*)_sample.ToPointer());
	}

	float calc_error(IntPtr _data, MlErrorType type, IntPtr resp)
	{
		return ((CvBoost*)m_pStatModel)->calc_error((CvMLData*)_data.ToPointer(), (int)type, (vector<float>*)resp.ToPointer());
	}

	float calc_error(IntPtr _data, MlErrorType type)
	{
		return ((CvBoost*)m_pStatModel)->calc_error((CvMLData*)_data.ToPointer(), (int)type);
	}

	void prune(Slice slice)
	{
		return ((CvBoost*)m_pStatModel)->prune(*(CvSlice*)&slice);
	}

	IntPtr get_active_vars(bool absolute_idx)
	{
		return IntPtr((CvMat*)((CvBoost*)m_pStatModel)->get_active_vars(absolute_idx));
	}

	IntPtr get_active_vars()
	{
		return IntPtr((CvMat*)((CvBoost*)m_pStatModel)->get_active_vars());
	}

	IntPtr get_weak_predictors()
	{
		return IntPtr((CvSeq*)((CvBoost*)m_pStatModel)->get_weak_predictors());
	}

	IntPtr get_weights()
	{
		return IntPtr((CvMat*)((CvBoost*)m_pStatModel)->get_weights());
	}

	IntPtr get_subtree_weights()
	{
		return IntPtr((CvMat*)((CvBoost*)m_pStatModel)->get_subtree_weights());
	}

	IntPtr get_weak_response()
	{
		return IntPtr((CvMat*)((CvBoost*)m_pStatModel)->get_weak_response());
	}

	IntPtr get_params()
	{
		return IntPtr((CvBoostParams*)&((CvBoost*)m_pStatModel)->get_params());
	}

	IntPtr get_data()
	{
		return IntPtr((CvDTreeTrainData*)((CvBoost*)m_pStatModel)->get_data());
	}
};

/****************************************************************************************\
*                              Artificial Neural Networks (ANN)                          *
\****************************************************************************************/
public ref class ANN_MLP : public StatModel
{
public:
	ANN_MLP()
	{
		m_pStatModel = new CvANN_MLP();
	}

	ANN_MLP(IntPtr _layer_sizes, ANNActivationFunction _activ_func, double _f_param1, double _f_param2)
	{
		m_pStatModel = new CvANN_MLP((CvMat*)_layer_sizes.ToPointer(), (int)_activ_func, _f_param1, _f_param2);
	}

	ANN_MLP(IntPtr _layer_sizes, ANNActivationFunction _activ_func, double _f_param1)
	{
		m_pStatModel = new CvANN_MLP((CvMat*)_layer_sizes.ToPointer(), (int)_activ_func, _f_param1);
	}

	ANN_MLP(IntPtr _layer_sizes, ANNActivationFunction _activ_func)
	{
		m_pStatModel = new CvANN_MLP((CvMat*)_layer_sizes.ToPointer(), (int)_activ_func);
	}

	ANN_MLP(IntPtr _layer_sizes)
	{
		m_pStatModel = new CvANN_MLP((CvMat*)_layer_sizes.ToPointer());
	}

	void create(IntPtr _layer_sizes, ANNActivationFunction _activ_func, double _f_param1, double _f_param2)
	{
		return ((CvANN_MLP*)m_pStatModel)->create((CvMat*)_layer_sizes.ToPointer(), (int)_activ_func, _f_param1, _f_param2);
	}

	void create(IntPtr _layer_sizes, ANNActivationFunction _activ_func, double _f_param1)
	{
		return ((CvANN_MLP*)m_pStatModel)->create((CvMat*)_layer_sizes.ToPointer(), (int)_activ_func, _f_param1);
	}

	void create(IntPtr _layer_sizes, ANNActivationFunction _activ_func)
	{
		return ((CvANN_MLP*)m_pStatModel)->create((CvMat*)_layer_sizes.ToPointer(), (int)_activ_func);
	}

	void create(IntPtr _layer_sizes)
	{
		return ((CvANN_MLP*)m_pStatModel)->create((CvMat*)_layer_sizes.ToPointer());
	}

	int train(IntPtr _inputs, IntPtr _outputs, IntPtr _sample_weights, 
		IntPtr _sample_idx, ANNMLPTrainParams _params, ANNTrainFlag flags)
	{
		return ((CvANN_MLP*)m_pStatModel)->train(
			(CvMat*)_inputs.ToPointer(), 
			(CvMat*)_outputs.ToPointer(), 
			(CvMat*)_sample_weights.ToPointer(), 
			(CvMat*)_sample_idx.ToPointer(), 
			*(CvANN_MLP_TrainParams*)&_params, 
			(int)flags);
	}

	int train(IntPtr _inputs, IntPtr _outputs, IntPtr _sample_weights, 
		IntPtr _sample_idx, ANNMLPTrainParams _params)
	{
		return ((CvANN_MLP*)m_pStatModel)->train(
			(CvMat*)_inputs.ToPointer(), 
			(CvMat*)_outputs.ToPointer(), 
			(CvMat*)_sample_weights.ToPointer(), 
			(CvMat*)_sample_idx.ToPointer(), 
			*(CvANN_MLP_TrainParams*)&_params);
	}

	int train(IntPtr _inputs, IntPtr _outputs, IntPtr _sample_weights, 
		IntPtr _sample_idx)
	{
		return ((CvANN_MLP*)m_pStatModel)->train(
			(CvMat*)_inputs.ToPointer(), 
			(CvMat*)_outputs.ToPointer(), 
			(CvMat*)_sample_weights.ToPointer(), 
			(CvMat*)_sample_idx.ToPointer());
	}

	int train(IntPtr _inputs, IntPtr _outputs, IntPtr _sample_weights)
	{
		return ((CvANN_MLP*)m_pStatModel)->train(
			(CvMat*)_inputs.ToPointer(), 
			(CvMat*)_outputs.ToPointer(), 
			(CvMat*)_sample_weights.ToPointer());
	}

	float predict(IntPtr _inputs, IntPtr _outputs)
	{
		return ((CvANN_MLP*)m_pStatModel)->predict((CvMat*)_inputs.ToPointer(), (CvMat*)_outputs.ToPointer());
	}

	int get_layer_count()
	{
		return ((CvANN_MLP*)m_pStatModel)->get_layer_count();
	}

	IntPtr get_layer_sizes()
	{
		return IntPtr((CvMat*)((CvANN_MLP*)m_pStatModel)->get_layer_sizes());
	}

	IntPtr get_weights(int layer)
	{
		return IntPtr(((CvANN_MLP*)m_pStatModel)->get_weights(layer));
	}
};

public ref class MLData
{
public:
	MLData()
	{
		m_pMlData = new CvMLData();
	}

	~MLData()
	{
		delete m_pMlData;
	}

	// returns:
	// 0 - OK  
	// 1 - file can not be opened or is not correct
	bool read_csv(IntPtr filename)
	{
		return m_pMlData->read_csv((char*)filename.ToPointer()) == 0;
	}

	IntPtr get_values()
	{
		return IntPtr((CvMat*)m_pMlData->get_values());
	}

	IntPtr get_responses()
	{
		return IntPtr((CvMat*)m_pMlData->get_responses());
	}

	IntPtr get_missing()
	{
		return IntPtr((CvMat*)m_pMlData->get_missing());
	}

	void set_response_idx(int idx )
	{
		return m_pMlData->set_response_idx(idx);
	}
	
	int get_response_idx()
	{
		return m_pMlData->get_response_idx();
	}

	IntPtr get_train_sample_idx()
	{
		return IntPtr((CvMat*)m_pMlData->get_train_sample_idx());
	}

	IntPtr get_test_sample_idx()
	{
		return IntPtr((CvMat*)m_pMlData->get_test_sample_idx());
	}

	void mix_train_and_test_idx()
	{
		return m_pMlData->mix_train_and_test_idx();
	}

	void set_train_test_split(IntPtr spl)
	{
		return m_pMlData->set_train_test_split((CvTrainTestSplit*)spl.ToPointer());
	}

	IntPtr get_var_idx()
	{
		return IntPtr((CvMat*)m_pMlData->get_missing());
	}

	void chahge_var_idx(int vi, bool state)
	{
		return m_pMlData->chahge_var_idx(vi, state);
	}

	IntPtr get_var_types()
	{
		return IntPtr((CvMat*)m_pMlData->get_missing());
	}

	int get_var_type( int var_idx )
	{
		return m_pMlData->get_var_type(var_idx); 
	}

	// following 2 methods enable to change vars type
	// use these methods to assign CV_VAR_CATEGORICAL type for categorical variable
	// with numerical labels; in the other cases var types are correctly determined automatically
	void set_var_types(IntPtr str)
	{
		return m_pMlData->set_var_types((char*)str.ToPointer());
	}

	// "ord[0-17],cat[18]", "ord[0,2,4,10-12], cat[1,3,5-9,13,14]",
	// "cat", "ord" (all vars are categorical/ordered)
	void change_var_type(int var_idx, MLVariableType type)
	{
		return m_pMlData->change_var_type(var_idx, (int)type);
	}

	void set_delimiter(char ch)
	{
		return m_pMlData->set_delimiter(ch);
	}

	char get_delimiter()
	{
		return m_pMlData->get_delimiter();
	}

	void set_miss_ch(char ch)
	{
		return m_pMlData->set_miss_ch(ch);
	}

	char get_miss_ch()
	{
		return m_pMlData->get_miss_ch();
	}

public:
	CvMLData* m_pMlData;
};
//////////////////////////////////////////////////////////////////////////
NAMESPACE_END
//////////////////////////////////////////////////////////////////////////